/*
 * SyncResource.java
 *
 * Created on April 12, 2007, 1:39 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.admin;

import java.util.logging.Level;
import org.atomojo.app.App;
import org.atomojo.app.InfosetRepresentation;
import org.atomojo.app.auth.AuthCredentials;
import org.atomojo.app.auth.AuthException;
import org.atomojo.app.auth.AuthService;
import org.atomojo.app.auth.User;
import org.atomojo.app.client.XMLRepresentationParser;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.XMLException;
import org.infoset.xml.util.DocumentDestination;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.CharacterSet;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;

/**
 *
 * @author alex
 */
public class UserResource extends ServerResource implements AdminXML
{
   static final String GROUPS_FACET = "groups";
   
   XMLRepresentationParser parser = new XMLRepresentationParser();
   String alias;
   String facet;
   String facetAlias;
   /** Creates a new instance of SyncResource */
   public UserResource() {
      setNegotiated(false);
   }

   protected void doInit() {
      alias = AdminApplication.getStringAttribute(getRequest(),"alias",null);
      facet = AdminApplication.getStringAttribute(getRequest(),"facet",null);
      facetAlias = AdminApplication.getStringAttribute(getRequest(),"facet-alias",null);
   }
      
   public Representation get()
   {
      if (facet!=null) {
         getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
         return null;
      }
         
      AuthService auth = (AuthService)getRequest().getAttributes().get(App.AUTH_SERVICE_ATTR);

      User user = null;
      try {
         ChallengeResponse transCred = getRequest().getChallengeResponse();
         AuthCredentials cred = new AuthCredentials(transCred.getScheme().toString(),transCred.getIdentifier(),new String(transCred.getSecret()));
         user = auth.getUser(cred,alias);
         if (user==null) {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return new StringRepresentation("User "+alias+" does not exist.");
         }
      } catch (AuthException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot get user to due exception: "+ex.getMessage(),ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Cannot get user due to database error.");
      }
      try {
         DocumentDestination dest = new DocumentDestination();
         toXML(user,dest);
         InfosetRepresentation rep = new InfosetRepresentation(MediaType.APPLICATION_XML,dest.getDocument());
         rep.setCharacterSet(CharacterSet.UTF_8);
         return rep;
      } catch (XMLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot build target list to due to XML exception: "+ex.getMessage(),ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Internal error, see logs.");
      }
   }
   
   public static void toXML(User user,ItemDestination dest)
      throws XMLException
   {
      ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
      dest.send(constructor.createDocument());
      Element userE = constructor.createElement(NM_USER);
      userE.setAttributeValue("alias",user.getAlias());
      userE.setAttributeValue("id",user.getId().toString());
      dest.send(userE);
      if (user.getName()!=null) {
         dest.send(constructor.createElement(NM_NAME));
         dest.send(constructor.createCharacters(user.getName()));
         dest.send(constructor.createElementEnd(NM_NAME));
      }
      if (user.getEmail()!=null) {
         dest.send(constructor.createElement(NM_EMAIL));
         dest.send(constructor.createCharacters(user.getEmail()));
         dest.send(constructor.createElementEnd(NM_EMAIL));
      }
      dest.send(constructor.createElementEnd(NM_USER));
      dest.send(constructor.createDocumentEnd());
   }
   
   public Representation post(Representation entity)
   {
      if (!XMLRepresentationParser.isXML(entity.getMediaType())) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Non-XML media type for entity body: "+entity.getMediaType().getName());
      }
      Document doc = null;
      try {
         doc = parser.load(entity);
      } catch (Exception ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("XML parse error: "+ex.getMessage());
      }
      
      Element top = doc.getDocumentElement();
      if (!top.getName().equals(NM_USER) && !top.getName().equals(NM_GROUP)) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Unknown document element: "+top.getName());
      }

      if (facet!=null && !facet.equals(GROUPS_FACET)) {
         getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
         return new StringRepresentation("Unknown facet "+facet);
      }
      
      AuthService auth = (AuthService)getRequest().getAttributes().get(App.AUTH_SERVICE_ATTR);

      ChallengeResponse transCred = getRequest().getChallengeResponse();
      AuthCredentials cred = new AuthCredentials(transCred.getScheme().toString(),transCred.getIdentifier(),new String(transCred.getSecret()));
      if (facet==null) {

         if (!top.getName().equals(NM_USER)) {
            getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("Document element "+top.getName()+" not allowed on user.");
         }
         
         String password = top.getAttributeValue("password");
         if (password!=null) {
            password = password.trim();
         }

         Element nameE = top.getFirstElementNamed(NM_NAME);
         String name = null;
         if (nameE!=null) {
            name = nameE.getText();
         }
         Element emailE = top.getFirstElementNamed(NM_EMAIL);
         String email = null;
         if (emailE!=null) {
            email = emailE.getText();
         }
         try {

            User user = auth.getUser(cred,alias);
            if (user!=null) {
               try {
                  if (nameE!=null || emailE!=null) {
                     // The name starts the same and can only be changed.  It can't be deleted
                     String newName = user.getName();
                     // Set it to the new name only if it was specified
                     if (name!=null) {
                        newName = name;
                     }
                     String newEmail = user.getEmail();
                     // Set to new e-mail if it exists
                     if (email!=null) {
                        newEmail = email;
                     }
                     // If the e-mail was missing, remove it
                     if (emailE==null) {
                        newEmail = null;
                     }
                     auth.updateUser(cred,alias,newName,newEmail);
                  }
                  if (password!=null) {
                     if (!auth.setPassword(cred,alias,password)) {
                        getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                        return null;
                     }
                  }
                  getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
                  return null;
               } catch (AuthException ex) {
                  getContext().getLogger().log(Level.SEVERE,"Cannot modify user "+alias+": "+ex.getMessage(),ex);
                  getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
                  return new StringRepresentation("Internal error, see logs.");
               }
            } else {
               getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
               return new StringRepresentation("User "+alias+" does not exist.");
            }
         } catch (AuthException ex) {
            getContext().getLogger().log(Level.SEVERE,"Cannot check user "+alias+": "+ex.getMessage(),ex);
            getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
            return new StringRepresentation("Internal error, see logs.");
         }
      } else if (facetAlias!=null) {
         getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
         return null;
      } else {
         if (!top.getName().equals(NM_GROUP)) {
            getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("Document element "+top.getName()+" not allowed to groups.");
         }
         String group = top.getAttributeValue("alias");
         if (group==null) {
            getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("The 'alias' attribute is missing.");
         }
    
         try {
            if (auth.addUserToGroup(cred,alias,group)) {
               getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
            } else {
               getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            }
            return null;
         } catch (AuthException ex) {
            getContext().getLogger().log(Level.SEVERE,"Cannot add user "+alias+" to group "+group,ex);
            getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
            return new StringRepresentation("Internal error, see logs.");
         }
      }
   }
   
   public Representation delete() {
      AuthService auth = (AuthService)getRequest().getAttributes().get(App.AUTH_SERVICE_ATTR);
      ChallengeResponse transCred = getRequest().getChallengeResponse();
      AuthCredentials cred = new AuthCredentials(transCred.getScheme().toString(),transCred.getIdentifier(),new String(transCred.getSecret()));
      if (facet!=null) {
         if (!facet.equals(GROUPS_FACET)) {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return new StringRepresentation("Unknown facet "+facet);
         } else if (facetAlias==null) {
            getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
            return null;
         } else {
            try {
               if (auth.removeUserFromGroup(cred,alias,facetAlias)) {
                  getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
               } else {
                  getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
               }
               return null;
            } catch (AuthException ex) {
               getContext().getLogger().log(Level.SEVERE,"Cannot remove user "+alias+" from group "+facetAlias+": "+ex.getMessage(),ex);
               getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
               return new StringRepresentation("Internal error, see logs.");
            }
         }
      } else {
         try {
            if (auth.deleteUser(cred,alias)) {
               getResponse().setStatus(Status.SUCCESS_NO_CONTENT);
            } else {
               getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            }
            return null;
         } catch (AuthException ex) {
            getContext().getLogger().log(Level.SEVERE,"Cannot delete user "+alias+": "+ex.getMessage(),ex);
            getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
            return new StringRepresentation("Internal error, see logs.");
         }
      }
   }
      
}
